/*
    Copyright 2006 Andrew Wilkinson <andrew@indiegigs.co.uk>

    This file is part of libgp2x.

    libgp2x is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    libgp2x is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with libgp2x; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>

#include "gp2x_internal.h"
#include "gp2x_message.h"

unsigned char GP2x_system_message_waiting();

void GP2x_sync() {
    GP2x_postMessage(GP2x_MESSAGE_SYNC, 0, 1);
}

long GP2x_postMessage(unsigned long message, unsigned long value, unsigned char await_return) {
    while((*GP2x_write_buffer_write+1) % GP2x_MESSAGE_BUFFER_SIZE == *GP2x_write_buffer_read);

    GP2x_write_buffer[*GP2x_write_buffer_write].message = message;
    GP2x_write_buffer[*GP2x_write_buffer_write].value = value;

    *GP2x_write_buffer_write = *GP2x_write_buffer_write+1;
    if(*GP2x_write_buffer_write == GP2x_MESSAGE_BUFFER_SIZE) {
        *GP2x_write_buffer_write = 0;
    }

    if(await_return) {
        long value;
        while(*GP2x_return_ready == 0) {
            if(GP2x_system_message_waiting()) {
                unsigned long m;
                unsigned long p;
                GP2x_poll(&m, &p);
            }
#ifdef HOST_PC
        sleep(0);
#endif
        }
        value = *GP2x_return_value;
        *GP2x_return_ready = 0;
        return value;
    } else {
        return 0;
    }
}

unsigned char GP2x_process_system_message(unsigned long* message, unsigned long* value) {
    switch(*message) {
    case GP2x_MESSAGE_SYNC:
        GP2x_return(1);
        break;
#ifndef GP2x_940
    case GP2x_MESSAGE_FPRINTF:
        {
        char* str = (char*)GP2x_convert_ptr_from(*value);
        if(*str == 1) {
            fprintf(stdout, "%s", (str+1));
        } else if(*str == 2)
            fprintf(stderr, "%s", (str+1));
        }
        GP2x_upper_memory_free((void*)*value);
        break;
    case GP2x_MESSAGE_940_QUIT:
        {
        GP2x_940_shutdown();
        }
        break;
#else
    case GP2x_MESSAGE_FLIP_SYNC:
        {
        GP2x_flip();
        }
        break;
    case GP2x_MESSAGE_FLIP_UNSYNC:
        {
        GP2x_flip_unsync();
        }
        break;
#endif
    default:
        if(*message >= 1<<25) {
            fprintf(stderr, "Unrecognized system message %li.\n", *message);
        }
        return 1;
    }
    return GP2x_poll(message, value);
}

void GP2x_wait_message(unsigned long* message, unsigned long* value) {
    while(!GP2x_poll(message, value)) {
#ifdef HOST_PC
        sleep(0);
#endif
    }
}

unsigned char GP2x_poll(unsigned long* message, unsigned long* value) {
    if(*GP2x_read_buffer_read == *GP2x_read_buffer_write) {
        return 0;
    } else {
        *message = GP2x_read_buffer[*GP2x_read_buffer_read].message;
        *value = GP2x_read_buffer[*GP2x_read_buffer_read].value;
        *GP2x_read_buffer_read = *GP2x_read_buffer_read + 1;
        if(*GP2x_read_buffer_read == GP2x_MESSAGE_BUFFER_SIZE) {
            *GP2x_read_buffer_read = 0;
        }
        if(*message >= 1<<25) {
            return GP2x_process_system_message(message, value);
        } else {
            return 1;
        }
    }
}

void GP2x_return(unsigned long value) {
     *GP2x_return_value = value;
     *GP2x_return_ready = 1;
}

unsigned char GP2x_system_message_waiting() {
    if(*GP2x_read_buffer_read == *GP2x_read_buffer_write) {
        return 0;
    } else {
        return GP2x_read_buffer[*GP2x_read_buffer_read].message >= 1<<25;
    }
}
